package edu.ntu.cloudroid.server.backendservice;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.google.appengine.api.datastore.Key;

import edu.ntu.cloudroid.model.PMF;
import edu.ntu.cloudroid.model.data.AbstractData;
import edu.ntu.cloudroid.model.friend.FriendData;
import edu.ntu.cloudroid.model.friend.GroupData;
import edu.ntu.cloudroid.model.friend.GroupInfo;
import edu.ntu.cloudroid.model.policy.AbstractPrivacyPreference;
import edu.ntu.cloudroid.model.profile.ProfileData;
import edu.ntu.cloudroid.server.backendservice.util.CloudDroidCache;

/**
 * @author ttadinh
 * Similar to FriendService.
 */
public class GroupService {
	private static CloudDroidCache<String, List<GroupData>> cache = new CloudDroidCache<String, List<GroupData>>(CloudDroidCache.SIZE);
	
	//adding a new group to the current profile
	public static GroupData addNewGroup(GroupInfo group) {		
		
		//try to delete it first
		//deleteGroup(person, groupName);
		
		PersistenceManager pm = PMF.get().getPersistenceManager();	
		GroupData gi = new GroupData();
		gi.setGroupName(group.getOwnerName()+"_"+group.getGroupName());
		gi.setMemberNames(group.getMembers());
		gi.setGroupOwnerName(group.getOwnerName());
		try {
			//Person q;			
			pm.currentTransaction().begin();		
			pm.makePersistent(gi);
			return gi;
		} finally {
			if (pm.currentTransaction().isActive()) {
				pm.currentTransaction().rollback();
			}
			pm.close();			
		}		
	}
		
	
	public static void deleteGroup(String owner, String groupName){
		GroupData gd = findGroupWithName(groupName);
		if (gd==null)
			return;

		//delete the policy
		PolicyService.deleteGroupPolicy(gd);
		//then from the datastore
		
			PersistenceManager pm = PMF.get().getPersistenceManager();
		try{
			pm.deletePersistent(gd);
		} finally {
			pm.close();
		}
	}
		
	
	//GROUP NAME MUST BE UNIQUE: username+_+group
	public static GroupData findGroupWithName(String groupName){
		PersistenceManager pm = PMF.get().getPersistenceManager();		
		try {
			Query locQuery = pm.newQuery(GroupData.class);
			locQuery.declareParameters("String gName");
			locQuery.setFilter("groupName == gName");
			//locQuery.setOrdering("timestamp DESC");

			@SuppressWarnings("unchecked")
			List<GroupData> locs = (List<GroupData>) locQuery.execute(groupName);
			if (locs.size()==0)
				return null;
			else{
				GroupData data = pm.detachCopy(locs.get(0));
				return data;
			}
		} 
		catch (Exception e){
			return null;
		}
		finally {
			pm.close();
		}
		
	}
		
	public static void addGroupMember(String groupOwner, String groupName,
			Set<String> members) throws Exception{
		GroupData gd = GroupService.findGroupWithName(groupName);
		for (String k : members) {
			gd.addMember(k);
		}
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(gd);
		} finally {
			pm.close();
		}
	}
	
	//if subject belongs to a friend group of resource, return the groups
	//else return empty list
	public static List<GroupData> getGroupData(String resource, String subject){
		List<GroupData> groups = getGroupByOwner(resource);
		List<GroupData> list = new ArrayList<GroupData>();
		for (GroupData g : groups){
			if (g.hasAMember(subject))
				list.add(g);
		}
		return list;
	}
	
	public static void deleteGroupMember(GroupData group, String member){
		if (group.getMemberKeys().contains(member)) {
			group.getMemberKeys().remove(member);
			PersistenceManager pm = PMF.get().getPersistenceManager();
			try {
				pm.makePersistent(group);
			} finally {
				pm.close();
			}
		}
	}
	
	
	
	
	//return all the group
	public static List<GroupData> getGroupByOwner(String owner){
		List<GroupData> cachedVal = cache.get(owner);
		if (cachedVal!=null)
			return cachedVal;
		
		PersistenceManager pm = PMF.get().getPersistenceManager();		
		try {
			Query locQuery = pm.newQuery(GroupData.class);
			locQuery.declareParameters("String gName");
			locQuery.setFilter("groupOwnerName == gName");
			//locQuery.setOrdering("timestamp DESC");

			@SuppressWarnings("unchecked")
			List<GroupData> locs = (List<GroupData>) locQuery.execute(owner);
			if (locs.size()==0)
				return null;
			else{
				List<GroupData> list = new ArrayList<GroupData>();
				for (GroupData data : locs)
					list.add(pm.detachCopy(locs.get(0)));
				cache.put(owner, list);
				return list;
			}
		} 
		catch (Exception e){
			return null;
		}
		finally {
			pm.close();
		}
	}
}
